﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2022-2022 LiLong                                              **
**  This file is part of BluetoothCpp.                                          **
**                                                                              **
**  BluetoothCpp is free software: you can redistribute it and/or modify        **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  BluetoothCpp is distributed in the hope that it will be useful,             **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with BluetoothCpp.  If not, see <https://www.gnu.org/licenses/>.      **
**********************************************************************************/
#include "Address.h"

#include <charconv>
#include <errno.h>
#include <format>
#include <ranges>

namespace BTH
{
struct Address::Impl
{
    unsigned long long addr { 0 };
};

Address::Address() noexcept : m_impl(std::make_unique<Impl>()) {}

Address::Address(std::string_view address) noexcept : Address()
{
    std::string addr(address.begin(), address.end());
    if (addr.length() == 17)
        std::erase(addr, ':');

    if (addr.length() == 12)
    {
        char* end;
        m_impl->addr = std::strtoull(addr.c_str(), &end, 16);
        if (!errno)
            clear();
    }
    else
    {
        m_impl->addr = 0;
    }
}

Address::Address(unsigned long long address) noexcept : Address() { m_impl->addr = address; }

Address::Address(const Address& other) noexcept : Address() { m_impl->addr = other.m_impl->addr; }

Address::~Address() noexcept {}

std::string Address::toString() const noexcept
{
    std::string addr;
    for (int i = 5; i >= 0; --i)
    {
        const unsigned char a = (m_impl->addr >> (i * 8)) & 0xff;
        addr.append(addr.empty() ? std::format("{:02X}", a) : std::format(":{:02X}", a));
    }
    return addr;
}

unsigned long long Address::toUInt64() const noexcept { return m_impl->addr; }

void Address::clear() noexcept { m_impl->addr = 0; }

bool Address::isNull() const noexcept { return m_impl->addr == 0; }

std::strong_ordering Address::operator<=>(const Address& rhs) const noexcept { return m_impl->addr <=> rhs.m_impl->addr; }

Address& Address::operator=(const Address& other)
{
    m_impl->addr = other.m_impl->addr;
    return *this;
}

} // namespace BTH
